home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  11.2 KB  |  455 lines

  1. /* Pulldown menu code.
  2.    Copyright (C) 1994 Miguel de Icaza.
  3.    
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2 of the License, or
  7.    (at your option) any later version.
  8.    
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #include <config.h>
  19. #include "tty.h"
  20. #include <string.h>
  21. #include <stdarg.h>
  22. #include <sys/types.h>
  23. #include <ctype.h>
  24. #include <malloc.h>
  25. #include "mad.h"
  26. #include "util.h"
  27. #include "menu.h"
  28. #include "dialog.h"
  29. #include "global.h"
  30. #include "color.h"
  31. #include "main.h"
  32. #include "mouse.h"
  33. #include "win.h"
  34. #include "key.h"    /* For mi_getch() */
  35.  
  36. /* "$Id: menu.c,v 1.18 1995/02/21 19:06:48 miguel Exp $" */
  37.  
  38. extern int is_right;
  39. int menubar_visible = 1;    /* This is the new default */
  40.  
  41. Menu create_menu (char *name, menu_entry *entries, int count)
  42. {
  43.     Menu menu;
  44.  
  45.     menu = (Menu) xmalloc (sizeof (*menu), "create_menu");
  46.     menu->count = count;
  47.     menu->max_entry_len = 0;
  48.     menu->entries = entries;
  49.     menu->name = name;
  50.     return menu;
  51. }
  52.  
  53. static void menubar_drop_compute (WMenu *menubar)
  54. {
  55.     const Menu menu = menubar->menu [menubar->selected];
  56.     int   max_entry_len = 0;
  57.     int i;
  58.     
  59.     for (i = 0; i < menu->count; i++)
  60.     max_entry_len = max (max_entry_len, strlen (menu->entries [i].text));
  61.     menubar->max_entry_len = max_entry_len = max (max_entry_len, 20);
  62. }
  63.  
  64. static void menubar_paint_idx (WMenu *menubar, int idx, int color)
  65. {
  66.     const Menu menu = menubar->menu [menubar->selected];
  67.     const int y = 2 + idx;
  68.     const int x = (menubar->selected * 12) + 1;
  69.  
  70.     widget_move (&menubar->widget, y, x);
  71.     attrset (color);
  72.     hline (' ', menubar->max_entry_len+2);
  73.     if (!*menu->entries [idx].text){
  74.         attrset (SELECTED_COLOR);
  75.         widget_move (&menubar->widget, y, x + 1);
  76.         hline (slow_terminal ? ' ' : ACS_HLINE, menubar->max_entry_len);
  77.     } else {
  78.     char *text = menu->entries [idx].text;
  79.     int  hotkey = menu->entries [idx].hot_key;
  80.     char *save;
  81.     
  82.         printw ("%c%-s", menu->entries [idx].first_letter, text);
  83.  
  84.     if (!slow_terminal){
  85.         save = text;
  86.  
  87.         /* First, try to highlight the hotkey */
  88.         while (*text && *text != hotkey)
  89.         text++;
  90.  
  91.         if (!*text)
  92.         text = save;
  93.         
  94.         if (*text){
  95.         widget_move (&menubar->widget, y, x+text-save+1);
  96.         attrset (color == MENU_SELECTED_COLOR ?
  97.              MENU_HOTSEL_COLOR : MENU_HOT_COLOR);
  98.         addch (*text);
  99.         }
  100.     }
  101.     }
  102.     widget_move (&menubar->widget, y, x + 1);
  103. }
  104.  
  105. static INLINE void menubar_draw_drop (WMenu *menubar)
  106. {
  107.     const int count = (menubar->menu [menubar->selected])->count;
  108.     int   i;
  109.     int   sel = menubar->subsel;
  110.     int   column = (menubar->selected * 12);
  111.  
  112.     attrset (SELECTED_COLOR);
  113.     draw_box (menubar->widget.parent,
  114.           menubar->widget.y+1, menubar->widget.x + column,
  115.           count+2, menubar->max_entry_len + 4);
  116.  
  117.     column++;
  118.     for (i = 0; i < count; i++){
  119.     if (i == sel)
  120.         continue;
  121.     menubar_paint_idx (menubar, i, MENU_ENTRY_COLOR);
  122.     }
  123.     menubar_paint_idx (menubar, sel, MENU_SELECTED_COLOR);
  124. }
  125.  
  126. static void menubar_draw (WMenu *menubar)
  127. {
  128.     const int items = menubar->items;
  129.     int   i;
  130.     
  131.     /* First draw the complete menubar */
  132.     attrset (SELECTED_COLOR);
  133.     widget_move (&menubar->widget, 0, 0);
  134.  
  135.     /* ncurses bug: it should work with hline but it does not */
  136.     for (i =  menubar->widget.cols; i; i--)
  137.     addch (' ');
  138.  
  139.     attrset (SELECTED_COLOR);
  140.     /* Now each one of the entries */
  141.     for (i = 0; i < items; i++){
  142.     if (menubar->active)
  143.         attrset(i == menubar->selected?MENU_SELECTED_COLOR:SELECTED_COLOR);
  144.     widget_move (&menubar->widget, 0, menubar->widget.x + 2 + (i * 12));
  145.     printw ("%s", menubar->menu [i]->name);
  146.     }
  147.  
  148.     if (menubar->dropped)
  149.     menubar_draw_drop (menubar);
  150.     else 
  151.     widget_move (&menubar->widget, 0, menubar->widget.x + 3 +
  152.              menubar->selected * 12);
  153. }
  154.  
  155. static INLINE void menubar_remove (WMenu *menubar)
  156. {
  157.     menubar->subsel = 0;
  158.     if (menubar->dropped){
  159.     menubar->dropped = 0;
  160.     do_refresh ();
  161.     menubar->dropped = 1;
  162.     }
  163. }
  164.  
  165. static void menubar_left (WMenu *menu)
  166. {
  167.     menubar_remove (menu);
  168.     menu->selected = (menu->selected - 1) % menu->items;
  169.     if (menu->selected < 0)
  170.     menu->selected = menu->items -1;
  171.     menubar_drop_compute (menu);
  172.     menubar_draw (menu);
  173. }
  174.  
  175. static void menubar_right (WMenu *menu)
  176. {
  177.     menubar_remove (menu);
  178.     menu->selected = (menu->selected + 1) % menu->items;
  179.     menubar_drop_compute (menu);
  180.     menubar_draw (menu);
  181. }
  182.  
  183. static void menubar_finish (WMenu *menubar)
  184. {
  185.     menubar->dropped = 0;
  186.     menubar->active = 0;
  187.     menubar->widget.lines = 1;
  188.     widget_want_hotkey (menubar->widget, 0);
  189.     dlg_select_nth_widget (menubar->widget.parent,
  190.                menubar->previous_selection);
  191.     do_refresh ();
  192. }
  193.  
  194. static void menubar_drop (WMenu *menubar, int selected)
  195. {
  196.     menubar->dropped = 1;
  197.     menubar->selected = selected;
  198.     menubar->subsel = 0;
  199.     menubar_drop_compute (menubar);
  200.     menubar_draw (menubar);
  201. }
  202.  
  203. static void menubar_execute (WMenu *menubar, int entry)
  204. {
  205.     const Menu menu = menubar->menu [menubar->selected];
  206.     
  207.     is_right = menubar->selected != 0;
  208.     (*menu->entries [entry].call_back)(0);
  209.     menubar_finish (menubar);
  210. }
  211.  
  212. static void menubar_move (WMenu *menubar, int step)
  213. {
  214.     const Menu menu = menubar->menu [menubar->selected];
  215.  
  216.     menubar_paint_idx (menubar, menubar->subsel, MENU_ENTRY_COLOR);
  217.     do {
  218.     menubar->subsel += step;
  219.     if (menubar->subsel < 0)
  220.         menubar->subsel = menu->count - 1;
  221.     
  222.     menubar->subsel %= menu->count;
  223.     } while  (!menu->entries [menubar->subsel].call_back);
  224.     menubar_paint_idx (menubar, menubar->subsel, MENU_SELECTED_COLOR);
  225. }
  226.  
  227. static int menubar_handle_key (WMenu *menubar, int key)
  228. {
  229.     int   i;
  230.  
  231.     /* Lowercase */
  232.     if (key < 256 && isascii (key)) /* Linux libc.so.5.x.x bug fix */
  233.     key = tolower (key);
  234.     
  235.     if (is_abort_char (key)){
  236.     menubar_finish (menubar);
  237.     return 1;
  238.     }
  239.  
  240.     if (key == KEY_LEFT || key == XCTRL('b')){
  241.     menubar_left (menubar);
  242.     return 1;
  243.     } else if (key == KEY_RIGHT || key == XCTRL ('f')){
  244.     menubar_right (menubar);
  245.     return 1;
  246.     }
  247.  
  248.     if (!menubar->dropped){
  249.     const int items = menubar->items;
  250.     for (i = 0; i < items; i++){
  251.         const Menu menu = menubar->menu [i];
  252.  
  253.         /* Hack, we should check for the upper case letter */
  254.         if (tolower (menu->name [1]) == key){
  255.         menubar_drop (menubar, i);
  256.         return 1; 
  257.         }
  258.     }
  259.     if (key == KEY_ENTER || key == XCTRL ('n') || key == KEY_DOWN
  260.         || key == '\n'){
  261.         menubar_drop (menubar, menubar->selected);
  262.         return 1;
  263.     }
  264.     return 1;
  265.     } else {
  266.     const int selected = menubar->selected;
  267.     const Menu menu = menubar->menu [selected];
  268.     const int items = menu->count;
  269.     char l;
  270.     int m;
  271.     
  272.     for (i = 0; i < items; i++){
  273.         if (!menu->entries [i].call_back)
  274.         continue;
  275.         
  276.         m = menu->entries [i].hot_key;
  277.         if (m < 256 && isascii (m))
  278.             m = tolower (m);
  279.         if (key != m)
  280.         continue;
  281.         
  282.         menubar_execute (menubar, i);
  283.         return 1;
  284.     }
  285.  
  286.     for (i = 0; i < items; i++){
  287.         l = tolower (menu->entries [i].text [0]);
  288.         if (l != key)
  289.         continue;
  290.         
  291.         menubar_execute (menubar, i);
  292.         return 1;
  293.     }
  294.     
  295.     if (key == KEY_ENTER || key == '\n'){
  296.         menubar_execute (menubar, menubar->subsel);
  297.         return 1;
  298.     }
  299.     
  300.     
  301.     if (key == KEY_DOWN || key == XCTRL ('n'))
  302.         menubar_move (menubar, 1);
  303.     
  304.     if (key == KEY_UP || key == XCTRL ('p'))
  305.         menubar_move (menubar, -1);
  306.     }
  307.     return 0;
  308. }
  309.  
  310. static int menubar_callback (Dlg_head *h, WMenu *menubar, int msg, int par)
  311. {
  312.     switch (msg){
  313.     /* We do not want the focus unless we have been activated */
  314.     case WIDGET_FOCUS:
  315.     if (menubar->active){
  316.         widget_want_cursor (menubar->widget, 1);
  317.  
  318.         /* Trick to get all the mouse events */
  319.         menubar->widget.lines = LINES;
  320.  
  321.         /* Trick to get all of the hotkeys */
  322.         widget_want_hotkey (menubar->widget, 1);
  323.         menubar->subsel = 0;
  324.         menubar_drop_compute (menubar);
  325.         menubar_draw (menubar);
  326.         return 1;
  327.     } else
  328.         return 0;
  329.  
  330.     /* We don't want the buttonbar to activate while using the menubar */
  331.     case WIDGET_HOTKEY:
  332.     case WIDGET_KEY:
  333.     if (menubar->active){
  334.         menubar_handle_key (menubar, par);
  335.         return 1;
  336.     } else
  337.         return 0;
  338.  
  339.     case WIDGET_CURSOR:
  340.     /* Put the cursor in a suitable place */
  341.     return 0;
  342.     
  343.     case WIDGET_UNFOCUS:
  344.     if (menubar->active)
  345.         return 0;
  346.     else {
  347.         widget_want_cursor (menubar->widget, 0);
  348.         return 1;
  349.     }
  350.  
  351.     case WIDGET_DRAW:
  352.     if (menubar_visible)
  353.         menubar_draw (menubar);
  354.     }
  355.     return default_proc (h, msg, par);
  356. }
  357.  
  358. static int menubar_event    (Gpm_Event *event, WMenu *menubar)
  359. {
  360.     int was_active;
  361.     int new_selection;
  362.     int left_x, right_x, bottom_y;
  363.  
  364.     if (!(event->type & (GPM_UP|GPM_DOWN|GPM_DRAG)))
  365.     return MOU_NORMAL;
  366.     
  367.     if (!menubar->dropped){
  368.     menubar->previous_selection = dlg_item_number(menubar->widget.parent);
  369.     menubar->active = 1;
  370.     menubar->dropped = 1;
  371.     was_active = 0;
  372.     } else
  373.     was_active = 1;
  374.  
  375.     /* Mouse operations on the menubar */
  376.     if (event->y == 1 || !was_active){
  377.     if (event->type & GPM_UP)
  378.         return MOU_NORMAL;
  379.     
  380.     new_selection = 0;
  381.     if (event->x < menubar->items * 13)
  382.         new_selection = event->x / 13;
  383.     else
  384.         new_selection = menubar->items - 1;
  385.     
  386.     if (!was_active){
  387.         menubar->selected = new_selection;
  388.         dlg_select_widget (menubar->widget.parent, menubar);
  389.         menubar_drop_compute (menubar);
  390.         menubar_draw (menubar);
  391.         return MOU_NORMAL;
  392.     }
  393.     
  394.     menubar_remove (menubar);
  395.  
  396.     menubar->selected = new_selection;
  397.  
  398.     menubar_drop_compute (menubar);
  399.     menubar_draw (menubar);
  400.     return MOU_NORMAL;
  401.     }
  402.  
  403.     if (!menubar->dropped)
  404.     return MOU_NORMAL;
  405.     
  406.     /* Ignore the events on anything below the third line */
  407.     if (event->y <= 2)
  408.     return MOU_NORMAL;
  409.     
  410.     /* Else, the mouse operation is on the menus or it is not */
  411.     left_x = menubar->selected * 12;
  412.     right_x = left_x + menubar->max_entry_len + 4;
  413.     bottom_y = (menubar->menu [menubar->selected])->count + 3;
  414.  
  415.     if ((event->x > left_x) && (event->x < right_x) && (event->y < bottom_y)){
  416.     int pos = event->y - 3;
  417.  
  418.     if (!menubar->menu [menubar->selected]->entries [pos].call_back)
  419.         return MOU_NORMAL;
  420.     
  421.     menubar_paint_idx (menubar, menubar->subsel, MENU_ENTRY_COLOR);
  422.     menubar->subsel = pos;
  423.     menubar_paint_idx (menubar, menubar->subsel, MENU_SELECTED_COLOR);
  424.  
  425.     if (event->type & GPM_UP)
  426.         menubar_execute (menubar, pos);
  427.     } else
  428.     if (event->type & GPM_DOWN)
  429.         menubar_finish (menubar);
  430.      
  431.     return MOU_NORMAL;
  432. }
  433.  
  434. static void menubar_destroy (WMenu *menubar)
  435. {
  436. }
  437.  
  438. WMenu *menubar_new (int y, int x, int cols, Menu menu [], int items)
  439. {
  440.     WMenu *menubar = (WMenu *) xmalloc (sizeof (WMenu), "menubar_new");
  441.  
  442.     init_widget (&menubar->widget, y, x, 1, cols,
  443.                  (callback_fn) menubar_callback,
  444.          (destroy_fn)  menubar_destroy,
  445.          (mouse_h)     menubar_event);
  446.     menubar->menu = menu;
  447.     menubar->active = 0;
  448.     menubar->dropped = 0;
  449.     menubar->items = items;
  450.     menubar->selected = 0;
  451.     widget_want_cursor (menubar->widget, 0);
  452.     
  453.     return menubar;
  454. }
  455.